#include <memory>
#include <sys/select.h>
#include "socket.hpp"

class src_fds{//辅助文件描述符集
public:
    src_fds():_max_fd(0){;}
    int set(int fd){
        if(fds[fd]==false){
            fds[fd]=true;
            if(fd>=_max_fd){_max_fd=fd+1;}
            return fd;
        }
        LOG(WARRING)<<"add repite fd";
        return -1;
    }
    int remove(int fd){
        if(fds[fd]==true){
            fds[fd]=false;
            if(fd==_max_fd-1){
                ResetMaxFd();//更新max_fd
            }
            return fd;
        }
        LOG(WARRING)<<"remove a no excist fd";
        return -1;
    }
    bool cheackfd(int fd){return fds[fd];}
    int max_fd(){ return _max_fd;}
    void clear(){//清除辅助文件描述符集
        for(int i=0;i<_max_fd;i++){
            fds[i]=false;
        }
    }
    void writefds(fd_set* fdset){//将辅助数组中的文件描述符，拷贝给文件描述符集
        for(int i=0;i<_max_fd;i++){
            if(fds[i]==true) FD_SET(i,fdset);
        }
    }
private:
    void ResetMaxFd(){
        int fd=_max_fd-1;
        for(int i=fd;i>=0;i--){
            if(fds[fd]==true){
                _max_fd=i+1;
                break;
            }
        }
    }
    bool fds[1024]={false};
    size_t _max_fd;
};

class server{
public:
    server(uint16_t port):_port(port){
    }
    void init(){
        _listenfd=std::make_unique<TcpSocket>(_port);
        _isrunning=true;
        _listenfd->BulitTcpSocket(_port);
        _rfds.set(_listenfd->Fd());
    }
    void start(){
        fd_set rfds;
        while(_isrunning){
            FD_ZERO(&rfds);
            _rfds.writefds(&rfds);
            int n=select(_rfds.max_fd(),&rfds,nullptr,nullptr,nullptr);
            switch (n)
            {
            case 0:
                LOG(INFO)<<"no I/O aready";//没有I/O事件发生
                break;
            case -1:
                LOG(ERROR)<<"select error:"<<strerror(errno);
                break;
            default:
                //处理I/O事件
                handle_rfds(&rfds);
                break;
            }
        }
    }
private:
    void handle_rfds(fd_set* fds){
        //1.处理listen_socket
        if(FD_ISSET(_listenfd->Fd(),fds)){//读取监听到的链接
            inetaddr client;
            int newfd=_listenfd->accept(&client);
            LOG(INFO)<<"新增用户:"<<client.addr();
            _rfds.set(newfd);
        }
        //2.处理其他socket
        for(int i=4;i<_rfds.max_fd();i++){
            if(i==_listenfd->Fd()) continue;
            if(FD_ISSET(i,fds)){//i对应的fd收到了数据，对该数据读取并处理
                char in_buffer[2048];
                int n=recv(i,in_buffer,sizeof(in_buffer),0);
                if(n==0){
                    LOG(INFO)<<"client :"<<i<<" 断开了链接";
                    close(i);
                    _rfds.remove(i);
                }
                else if(n>0){
                    in_buffer[n]='\0';
                    std::cout<<"client["<<i<<"] say#"<<in_buffer<<std::endl;
                    std::string recv_mesg="echo#";
                    recv_mesg+=in_buffer;
                    send(i,recv_mesg.c_str(),recv_mesg.size(),0);
                }
                if(n==-1){
                    LOG(ERROR)<<"fd :"<<i<<"is error"<<strerror(errno);
                }
            }
        }
    }
    std::unique_ptr<Socket> _listenfd;
    uint16_t _port;
    src_fds _rfds;//只读属性的fds
    bool _isrunning;
};